File: | var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/cxxalloc.h |
Warning: | line 51, column 10 Memory allocated by 'operator new' should be deallocated by 'delete', not 'free()' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||||||
2 | * Copyright 2017 Google Inc. | ||||||||
3 | * | ||||||||
4 | * Use of this source code is governed by a BSD-style license that can be | ||||||||
5 | * found in the LICENSE file. | ||||||||
6 | */ | ||||||||
7 | #include "include/core/SkVertices.h" | ||||||||
8 | |||||||||
9 | #include "include/core/SkTypes.h" | ||||||||
10 | #include "include/private/base/SkMalloc.h" | ||||||||
11 | #include "include/private/base/SkTo.h" | ||||||||
12 | #include "src/base/SkSafeMath.h" | ||||||||
13 | #include "src/core/SkPicturePriv.h" | ||||||||
14 | #include "src/core/SkReadBuffer.h" | ||||||||
15 | #include "src/core/SkSafeRange.h" | ||||||||
16 | #include "src/core/SkVerticesPriv.h" | ||||||||
17 | #include "src/core/SkWriteBuffer.h" | ||||||||
18 | |||||||||
19 | #include <atomic> | ||||||||
20 | #include <new> | ||||||||
21 | #include <utility> | ||||||||
22 | |||||||||
23 | static uint32_t next_id() { | ||||||||
24 | static std::atomic<uint32_t> nextID{1}; | ||||||||
25 | |||||||||
26 | uint32_t id; | ||||||||
27 | do { | ||||||||
28 | id = nextID.fetch_add(1, std::memory_order_relaxed); | ||||||||
29 | } while (id == SK_InvalidGenID); | ||||||||
30 | return id; | ||||||||
31 | } | ||||||||
32 | |||||||||
33 | struct SkVertices::Desc { | ||||||||
34 | VertexMode fMode; | ||||||||
35 | int fVertexCount, | ||||||||
36 | fIndexCount; | ||||||||
37 | bool fHasTexs, | ||||||||
38 | fHasColors; | ||||||||
39 | }; | ||||||||
40 | |||||||||
41 | struct SkVertices::Sizes { | ||||||||
42 | Sizes(const Desc& desc) { | ||||||||
43 | SkSafeMath safe; | ||||||||
44 | |||||||||
45 | fVSize = safe.mul(desc.fVertexCount, sizeof(SkPoint)); | ||||||||
46 | fTSize = desc.fHasTexs ? safe.mul(desc.fVertexCount, sizeof(SkPoint)) : 0; | ||||||||
47 | fCSize = desc.fHasColors ? safe.mul(desc.fVertexCount, sizeof(SkColor)) : 0; | ||||||||
48 | |||||||||
49 | fBuilderTriFanISize = 0; | ||||||||
50 | fISize = safe.mul(desc.fIndexCount, sizeof(uint16_t)); | ||||||||
51 | if (kTriangleFan_VertexMode == desc.fMode) { | ||||||||
52 | int numFanTris = 0; | ||||||||
53 | if (desc.fIndexCount) { | ||||||||
54 | fBuilderTriFanISize = fISize; | ||||||||
55 | numFanTris = desc.fIndexCount - 2; | ||||||||
56 | } else { | ||||||||
57 | numFanTris = desc.fVertexCount - 2; | ||||||||
58 | // By forcing this to become indexed we are adding a constraint to the maximum | ||||||||
59 | // number of vertices. | ||||||||
60 | if (desc.fVertexCount > (SkTo<int>(UINT16_MAX(65535)) + 1)) { | ||||||||
61 | sk_bzero(this, sizeof(*this)); | ||||||||
62 | return; | ||||||||
63 | } | ||||||||
64 | } | ||||||||
65 | if (numFanTris <= 0) { | ||||||||
66 | sk_bzero(this, sizeof(*this)); | ||||||||
67 | return; | ||||||||
68 | } | ||||||||
69 | fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t)); | ||||||||
70 | } | ||||||||
71 | |||||||||
72 | fTotal = safe.add(sizeof(SkVertices), | ||||||||
73 | safe.add(fVSize, | ||||||||
74 | safe.add(fTSize, | ||||||||
75 | safe.add(fCSize, | ||||||||
76 | fISize)))); | ||||||||
77 | |||||||||
78 | if (safe.ok()) { | ||||||||
79 | fArrays = fVSize + fTSize + fCSize + fISize; // just the sum of the arrays | ||||||||
80 | } else { | ||||||||
81 | sk_bzero(this, sizeof(*this)); | ||||||||
82 | } | ||||||||
83 | } | ||||||||
84 | |||||||||
85 | bool isValid() const { return fTotal != 0; } | ||||||||
86 | |||||||||
87 | size_t fTotal = 0; // size of entire SkVertices allocation (obj + arrays) | ||||||||
88 | size_t fArrays; // size of all the data arrays (V + D + T + C + I) | ||||||||
89 | size_t fVSize; | ||||||||
90 | size_t fTSize; | ||||||||
91 | size_t fCSize; | ||||||||
92 | size_t fISize; | ||||||||
93 | |||||||||
94 | // For indexed tri-fans this is the number of amount of space fo indices needed in the builder | ||||||||
95 | // before conversion to indexed triangles (or zero if not indexed or not a triangle fan). | ||||||||
96 | size_t fBuilderTriFanISize; | ||||||||
97 | }; | ||||||||
98 | |||||||||
99 | SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, | ||||||||
100 | uint32_t builderFlags) { | ||||||||
101 | bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag); | ||||||||
102 | bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag); | ||||||||
103 | this->init({mode, vertexCount, indexCount, hasTexs, hasColors}); | ||||||||
104 | } | ||||||||
105 | |||||||||
106 | SkVertices::Builder::Builder(const Desc& desc) { | ||||||||
107 | this->init(desc); | ||||||||
108 | } | ||||||||
109 | |||||||||
110 | void SkVertices::Builder::init(const Desc& desc) { | ||||||||
111 | Sizes sizes(desc); | ||||||||
112 | if (!sizes.isValid()) { | ||||||||
113 | SkASSERT(!this->isValid())static_cast<void>( __builtin_expect(static_cast<bool >(!this->isValid()), 1) ? static_cast<void>(0) : [ ]{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 113, "!this->isValid()"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
114 | return; | ||||||||
115 | } | ||||||||
116 | |||||||||
117 | void* storage = ::operator new (sizes.fTotal); | ||||||||
118 | if (sizes.fBuilderTriFanISize
| ||||||||
119 | fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]); | ||||||||
120 | } | ||||||||
121 | |||||||||
122 | fVertices.reset(new (storage) SkVertices); | ||||||||
123 | |||||||||
124 | // need to point past the object to store the arrays | ||||||||
125 | char* ptr = (char*)storage + sizeof(SkVertices); | ||||||||
126 | |||||||||
127 | // return the original ptr (or null), but then advance it by size | ||||||||
128 | auto advance = [&ptr](size_t size) { | ||||||||
129 | char* new_ptr = size ? ptr : nullptr; | ||||||||
130 | ptr += size; | ||||||||
131 | return new_ptr; | ||||||||
132 | }; | ||||||||
133 | |||||||||
134 | fVertices->fPositions = (SkPoint*) advance(sizes.fVSize); | ||||||||
135 | fVertices->fTexs = (SkPoint*) advance(sizes.fTSize); | ||||||||
136 | fVertices->fColors = (SkColor*) advance(sizes.fCSize); | ||||||||
137 | fVertices->fIndices = (uint16_t*)advance(sizes.fISize); | ||||||||
138 | |||||||||
139 | fVertices->fVertexCount = desc.fVertexCount; | ||||||||
140 | fVertices->fIndexCount = desc.fIndexCount; | ||||||||
141 | fVertices->fMode = desc.fMode; | ||||||||
142 | |||||||||
143 | // We defer assigning fBounds and fUniqueID until detach() is called | ||||||||
144 | } | ||||||||
145 | |||||||||
146 | sk_sp<SkVertices> SkVertices::Builder::detach() { | ||||||||
147 | if (fVertices) { | ||||||||
148 | fVertices->fBounds.setBounds(fVertices->fPositions, fVertices->fVertexCount); | ||||||||
149 | if (fVertices->fMode == kTriangleFan_VertexMode) { | ||||||||
150 | if (fIntermediateFanIndices) { | ||||||||
151 | SkASSERT(fVertices->fIndexCount)static_cast<void>( __builtin_expect(static_cast<bool >(fVertices->fIndexCount), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 151, "fVertices->fIndexCount"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
152 | auto tempIndices = this->indices(); | ||||||||
153 | for (int t = 0; t < fVertices->fIndexCount - 2; ++t) { | ||||||||
154 | fVertices->fIndices[3 * t + 0] = tempIndices[0]; | ||||||||
155 | fVertices->fIndices[3 * t + 1] = tempIndices[t + 1]; | ||||||||
156 | fVertices->fIndices[3 * t + 2] = tempIndices[t + 2]; | ||||||||
157 | } | ||||||||
158 | fVertices->fIndexCount = 3 * (fVertices->fIndexCount - 2); | ||||||||
159 | } else { | ||||||||
160 | SkASSERT(!fVertices->fIndexCount)static_cast<void>( __builtin_expect(static_cast<bool >(!fVertices->fIndexCount), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 160, "!fVertices->fIndexCount"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
161 | for (int t = 0; t < fVertices->fVertexCount - 2; ++t) { | ||||||||
162 | fVertices->fIndices[3 * t + 0] = 0; | ||||||||
163 | fVertices->fIndices[3 * t + 1] = SkToU16(t + 1); | ||||||||
164 | fVertices->fIndices[3 * t + 2] = SkToU16(t + 2); | ||||||||
165 | } | ||||||||
166 | fVertices->fIndexCount = 3 * (fVertices->fVertexCount - 2); | ||||||||
167 | } | ||||||||
168 | fVertices->fMode = kTriangles_VertexMode; | ||||||||
169 | } | ||||||||
170 | fVertices->fUniqueID = next_id(); | ||||||||
171 | return std::move(fVertices); // this will null fVertices after the return | ||||||||
172 | } | ||||||||
173 | return nullptr; | ||||||||
174 | } | ||||||||
175 | |||||||||
176 | SkPoint* SkVertices::Builder::positions() { | ||||||||
177 | return fVertices ? const_cast<SkPoint*>(fVertices->fPositions) : nullptr; | ||||||||
178 | } | ||||||||
179 | |||||||||
180 | SkPoint* SkVertices::Builder::texCoords() { | ||||||||
181 | return fVertices ? const_cast<SkPoint*>(fVertices->fTexs) : nullptr; | ||||||||
182 | } | ||||||||
183 | |||||||||
184 | SkColor* SkVertices::Builder::colors() { | ||||||||
185 | return fVertices ? const_cast<SkColor*>(fVertices->fColors) : nullptr; | ||||||||
186 | } | ||||||||
187 | |||||||||
188 | uint16_t* SkVertices::Builder::indices() { | ||||||||
189 | if (!fVertices) { | ||||||||
190 | return nullptr; | ||||||||
191 | } | ||||||||
192 | if (fIntermediateFanIndices) { | ||||||||
193 | return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get()); | ||||||||
194 | } | ||||||||
195 | return const_cast<uint16_t*>(fVertices->fIndices); | ||||||||
196 | } | ||||||||
197 | |||||||||
198 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||||
199 | |||||||||
200 | sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount, | ||||||||
201 | const SkPoint pos[], const SkPoint texs[], | ||||||||
202 | const SkColor colors[], | ||||||||
203 | int indexCount, const uint16_t indices[]) { | ||||||||
204 | auto desc = Desc{mode, vertexCount, indexCount, !!texs, !!colors}; | ||||||||
205 | Builder builder(desc); | ||||||||
206 | if (!builder.isValid()) { | ||||||||
207 | return nullptr; | ||||||||
208 | } | ||||||||
209 | |||||||||
210 | Sizes sizes(desc); | ||||||||
211 | SkASSERT(sizes.isValid())static_cast<void>( __builtin_expect(static_cast<bool >(sizes.isValid()), 1) ? static_cast<void>(0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 211, "sizes.isValid()"); ; sk_abort_no_print(); } while (false ); } } while(false); }() ); | ||||||||
212 | sk_careful_memcpy(builder.positions(), pos, sizes.fVSize); | ||||||||
213 | sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize); | ||||||||
214 | sk_careful_memcpy(builder.colors(), colors, sizes.fCSize); | ||||||||
215 | size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize; | ||||||||
216 | sk_careful_memcpy(builder.indices(), indices, isize); | ||||||||
217 | |||||||||
218 | return builder.detach(); | ||||||||
219 | } | ||||||||
220 | |||||||||
221 | size_t SkVertices::approximateSize() const { | ||||||||
222 | return this->getSizes().fTotal; | ||||||||
223 | } | ||||||||
224 | |||||||||
225 | SkVertices::Sizes SkVertices::getSizes() const { | ||||||||
226 | Sizes sizes({fMode, fVertexCount, fIndexCount, !!fTexs, !!fColors}); | ||||||||
227 | SkASSERT(sizes.isValid())static_cast<void>( __builtin_expect(static_cast<bool >(sizes.isValid()), 1) ? static_cast<void>(0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 227, "sizes.isValid()"); ; sk_abort_no_print(); } while (false ); } } while(false); }() ); | ||||||||
228 | return sizes; | ||||||||
229 | } | ||||||||
230 | |||||||||
231 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||||
232 | |||||||||
233 | // storage = packed | vertex_count | index_count | attr_count | ||||||||
234 | // | pos[] | custom[] | texs[] | colors[] | indices[] | ||||||||
235 | |||||||||
236 | #define kMode_Mask0x0FF 0x0FF | ||||||||
237 | #define kHasTexs_Mask0x100 0x100 | ||||||||
238 | #define kHasColors_Mask0x200 0x200 | ||||||||
239 | |||||||||
240 | void SkVerticesPriv::encode(SkWriteBuffer& buffer) const { | ||||||||
241 | // packed has room for additional flags in the future | ||||||||
242 | uint32_t packed = static_cast<uint32_t>(fVertices->fMode); | ||||||||
243 | SkASSERT((packed & ~kMode_Mask) == 0)static_cast<void>( __builtin_expect(static_cast<bool >((packed & ~0x0FF) == 0), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 243, "(packed & ~0x0FF) == 0"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); // our mode fits in the mask bits | ||||||||
244 | if (fVertices->fTexs) { | ||||||||
245 | packed |= kHasTexs_Mask0x100; | ||||||||
246 | } | ||||||||
247 | if (fVertices->fColors) { | ||||||||
248 | packed |= kHasColors_Mask0x200; | ||||||||
249 | } | ||||||||
250 | |||||||||
251 | SkVertices::Sizes sizes = fVertices->getSizes(); | ||||||||
252 | SkASSERT(!sizes.fBuilderTriFanISize)static_cast<void>( __builtin_expect(static_cast<bool >(!sizes.fBuilderTriFanISize), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/src/core/SkVertices.cpp" , 252, "!sizes.fBuilderTriFanISize"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
253 | |||||||||
254 | // Header | ||||||||
255 | buffer.writeUInt(packed); | ||||||||
256 | buffer.writeInt(fVertices->fVertexCount); | ||||||||
257 | buffer.writeInt(fVertices->fIndexCount); | ||||||||
258 | |||||||||
259 | // Data arrays | ||||||||
260 | buffer.writeByteArray(fVertices->fPositions, sizes.fVSize); | ||||||||
261 | buffer.writeByteArray(fVertices->fTexs, sizes.fTSize); | ||||||||
262 | buffer.writeByteArray(fVertices->fColors, sizes.fCSize); | ||||||||
263 | // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version | ||||||||
264 | buffer.writeByteArray(fVertices->fIndices, sizes.fISize); | ||||||||
265 | } | ||||||||
266 | |||||||||
267 | sk_sp<SkVertices> SkVerticesPriv::Decode(SkReadBuffer& buffer) { | ||||||||
268 | auto decode = [](SkReadBuffer& buffer) -> sk_sp<SkVertices> { | ||||||||
269 | SkSafeRange safe; | ||||||||
270 | bool hasCustomData = buffer.isVersionLT(SkPicturePriv::kVerticesRemoveCustomData_Version); | ||||||||
271 | |||||||||
272 | const uint32_t packed = buffer.readUInt(); | ||||||||
273 | const int vertexCount = safe.checkGE(buffer.readInt(), 0); | ||||||||
274 | const int indexCount = safe.checkGE(buffer.readInt(), 0); | ||||||||
275 | const int attrCount = hasCustomData
| ||||||||
276 | const SkVertices::VertexMode mode = safe.checkLE<SkVertices::VertexMode>( | ||||||||
277 | packed & kMode_Mask0x0FF, SkVertices::kLast_VertexMode); | ||||||||
278 | const bool hasTexs = SkToBool(packed & kHasTexs_Mask0x100); | ||||||||
279 | const bool hasColors = SkToBool(packed & kHasColors_Mask0x200); | ||||||||
280 | |||||||||
281 | // Check that the header fields and buffer are valid. If this is data with the experimental | ||||||||
282 | // custom attributes feature - we don't support that any more. | ||||||||
283 | // We also don't support serialized triangle-fan data. We stopped writing that long ago, | ||||||||
284 | // so it should never appear in valid encoded data. | ||||||||
285 | if (!safe || !buffer.isValid() || attrCount
| ||||||||
286 | mode == SkVertices::kTriangleFan_VertexMode) { | ||||||||
287 | return nullptr; | ||||||||
288 | } | ||||||||
289 | |||||||||
290 | const SkVertices::Desc desc{mode, vertexCount, indexCount, hasTexs, hasColors}; | ||||||||
291 | SkVertices::Sizes sizes(desc); | ||||||||
292 | if (!sizes.isValid() || sizes.fArrays > buffer.available()) { | ||||||||
293 | return nullptr; | ||||||||
294 | } | ||||||||
295 | |||||||||
296 | SkVertices::Builder builder(desc); | ||||||||
297 | if (!builder.isValid()) { | ||||||||
298 | return nullptr; | ||||||||
299 | } | ||||||||
300 | |||||||||
301 | buffer.readByteArray(builder.positions(), sizes.fVSize); | ||||||||
302 | if (hasCustomData
| ||||||||
303 | size_t customDataSize = 0; | ||||||||
304 | buffer.skipByteArray(&customDataSize); | ||||||||
305 | if (customDataSize != 0) { | ||||||||
306 | return nullptr; | ||||||||
307 | } | ||||||||
308 | } | ||||||||
309 | buffer.readByteArray(builder.texCoords(), sizes.fTSize); | ||||||||
310 | buffer.readByteArray(builder.colors(), sizes.fCSize); | ||||||||
311 | buffer.readByteArray(builder.indices(), sizes.fISize); | ||||||||
312 | |||||||||
313 | if (!buffer.isValid()) { | ||||||||
314 | return nullptr; | ||||||||
315 | } | ||||||||
316 | |||||||||
317 | if (indexCount > 0) { | ||||||||
318 | // validate that the indices are in range | ||||||||
319 | const uint16_t* indices = builder.indices(); | ||||||||
320 | for (int i = 0; i < indexCount; ++i) { | ||||||||
321 | if (indices[i] >= (unsigned)vertexCount) { | ||||||||
322 | return nullptr; | ||||||||
323 | } | ||||||||
324 | } | ||||||||
325 | } | ||||||||
326 | |||||||||
327 | return builder.detach(); | ||||||||
328 | }; | ||||||||
329 | |||||||||
330 | if (auto verts = decode(buffer)) { | ||||||||
| |||||||||
331 | return verts; | ||||||||
332 | } | ||||||||
333 | buffer.validate(false); | ||||||||
334 | return nullptr; | ||||||||
335 | } | ||||||||
336 | |||||||||
337 | void SkVertices::operator delete(void* p) { | ||||||||
338 | ::operator delete(p); | ||||||||
339 | } |
1 | /* |
2 | * Copyright 2017 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkVertices_DEFINED |
9 | #define SkVertices_DEFINED |
10 | |
11 | #include "include/core/SkColor.h" |
12 | #include "include/core/SkPoint.h" |
13 | #include "include/core/SkRect.h" |
14 | #include "include/core/SkRefCnt.h" |
15 | #include "include/private/base/SkAPI.h" |
16 | |
17 | #include <cstddef> |
18 | #include <cstdint> |
19 | #include <memory> |
20 | |
21 | class SkVerticesPriv; |
22 | |
23 | /** |
24 | * An immutable set of vertex data that can be used with SkCanvas::drawVertices. |
25 | */ |
26 | class SK_API SkVertices : public SkNVRefCnt<SkVertices> { |
27 | struct Desc; |
28 | struct Sizes; |
29 | public: |
30 | enum VertexMode { |
31 | kTriangles_VertexMode, |
32 | kTriangleStrip_VertexMode, |
33 | kTriangleFan_VertexMode, |
34 | |
35 | kLast_VertexMode = kTriangleFan_VertexMode, |
36 | }; |
37 | |
38 | /** |
39 | * Create a vertices by copying the specified arrays. texs, colors may be nullptr, |
40 | * and indices is ignored if indexCount == 0. |
41 | */ |
42 | static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount, |
43 | const SkPoint positions[], |
44 | const SkPoint texs[], |
45 | const SkColor colors[], |
46 | int indexCount, |
47 | const uint16_t indices[]); |
48 | |
49 | static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount, |
50 | const SkPoint positions[], |
51 | const SkPoint texs[], |
52 | const SkColor colors[]) { |
53 | return MakeCopy(mode, |
54 | vertexCount, |
55 | positions, |
56 | texs, |
57 | colors, |
58 | 0, |
59 | nullptr); |
60 | } |
61 | |
62 | enum BuilderFlags { |
63 | kHasTexCoords_BuilderFlag = 1 << 0, |
64 | kHasColors_BuilderFlag = 1 << 1, |
65 | }; |
66 | class SK_API Builder { |
67 | public: |
68 | Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags); |
69 | |
70 | bool isValid() const { return fVertices != nullptr; } |
71 | |
72 | SkPoint* positions(); |
73 | uint16_t* indices(); // returns null if there are no indices |
74 | |
75 | // If we have custom attributes, these will always be null |
76 | SkPoint* texCoords(); // returns null if there are no texCoords |
77 | SkColor* colors(); // returns null if there are no colors |
78 | |
79 | // Detach the built vertices object. After the first call, this will always return null. |
80 | sk_sp<SkVertices> detach(); |
81 | |
82 | private: |
83 | Builder(const Desc&); |
84 | |
85 | void init(const Desc&); |
86 | |
87 | // holds a partially complete object. only completed in detach() |
88 | sk_sp<SkVertices> fVertices; |
89 | // Extra storage for intermediate vertices in the case where the client specifies indexed |
90 | // triangle fans. These get converted to indexed triangles when the Builder is finalized. |
91 | std::unique_ptr<uint8_t[]> fIntermediateFanIndices; |
92 | |
93 | friend class SkVertices; |
94 | friend class SkVerticesPriv; |
95 | }; |
96 | |
97 | uint32_t uniqueID() const { return fUniqueID; } |
98 | const SkRect& bounds() const { return fBounds; } |
99 | |
100 | // returns approximate byte size of the vertices object |
101 | size_t approximateSize() const; |
102 | |
103 | // Provides access to functions that aren't part of the public API. |
104 | SkVerticesPriv priv(); |
105 | const SkVerticesPriv priv() const; // NOLINT(readability-const-return-type) |
106 | |
107 | private: |
108 | SkVertices() {} |
109 | |
110 | friend class SkVerticesPriv; |
111 | |
112 | // these are needed since we've manually sized our allocation (see Builder::init) |
113 | friend class SkNVRefCnt<SkVertices>; |
114 | void operator delete(void* p); |
115 | |
116 | Sizes getSizes() const; |
117 | |
118 | // we store this first, to pair with the refcnt in our base-class, so we don't have an |
119 | // unnecessary pad between it and the (possibly 8-byte aligned) ptrs. |
120 | uint32_t fUniqueID; |
121 | |
122 | // these point inside our allocation, so none of these can be "freed" |
123 | SkPoint* fPositions; // [vertexCount] |
124 | uint16_t* fIndices; // [indexCount] or null |
125 | SkPoint* fTexs; // [vertexCount] or null |
126 | SkColor* fColors; // [vertexCount] or null |
127 | |
128 | SkRect fBounds; // computed to be the union of the fPositions[] |
129 | int fVertexCount; |
130 | int fIndexCount; |
131 | |
132 | VertexMode fMode; |
133 | // below here is where the actual array data is stored. |
134 | }; |
135 | |
136 | #endif |
1 | /* | ||||||||
2 | * Copyright 2006 The Android Open Source Project | ||||||||
3 | * | ||||||||
4 | * Use of this source code is governed by a BSD-style license that can be | ||||||||
5 | * found in the LICENSE file. | ||||||||
6 | */ | ||||||||
7 | |||||||||
8 | #ifndef SkRefCnt_DEFINED | ||||||||
9 | #define SkRefCnt_DEFINED | ||||||||
10 | |||||||||
11 | #include "include/core/SkTypes.h" | ||||||||
12 | #include "include/private/base/SkDebug.h" | ||||||||
13 | |||||||||
14 | #include <atomic> | ||||||||
15 | #include <cstddef> | ||||||||
16 | #include <cstdint> | ||||||||
17 | #include <iosfwd> | ||||||||
18 | #include <type_traits> | ||||||||
19 | #include <utility> | ||||||||
20 | |||||||||
21 | /** \class SkRefCntBase | ||||||||
22 | |||||||||
23 | SkRefCntBase is the base class for objects that may be shared by multiple | ||||||||
24 | objects. When an existing owner wants to share a reference, it calls ref(). | ||||||||
25 | When an owner wants to release its reference, it calls unref(). When the | ||||||||
26 | shared object's reference count goes to zero as the result of an unref() | ||||||||
27 | call, its (virtual) destructor is called. It is an error for the | ||||||||
28 | destructor to be called explicitly (or via the object going out of scope on | ||||||||
29 | the stack or calling delete) if getRefCnt() > 1. | ||||||||
30 | */ | ||||||||
31 | class SK_API SkRefCntBase { | ||||||||
32 | public: | ||||||||
33 | /** Default construct, initializing the reference count to 1. | ||||||||
34 | */ | ||||||||
35 | SkRefCntBase() : fRefCnt(1) {} | ||||||||
36 | |||||||||
37 | /** Destruct, asserting that the reference count is 1. | ||||||||
38 | */ | ||||||||
39 | virtual ~SkRefCntBase() { | ||||||||
40 | #ifdef SK_DEBUG | ||||||||
41 | SkASSERTF(this->getRefCnt() == 1, "fRefCnt was %d", this->getRefCnt())static_cast<void>( __builtin_expect(static_cast<bool >(this->getRefCnt() == 1), 1) ? static_cast<void> (0) : [&]{ do { if (sk_abort_is_enabled()) { do { SkDebugf ("%s:%d" ": fatal error: \"" "assertf(%s): " "fRefCnt was %d" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 41, "this->getRefCnt() == 1", this->getRefCnt()); ; sk_abort_no_print (); } while (false); } } while(false); }() ); | ||||||||
42 | // illegal value, to catch us if we reuse after delete | ||||||||
43 | fRefCnt.store(0, std::memory_order_relaxed); | ||||||||
44 | #endif | ||||||||
45 | } | ||||||||
46 | |||||||||
47 | /** May return true if the caller is the only owner. | ||||||||
48 | * Ensures that all previous owner's actions are complete. | ||||||||
49 | */ | ||||||||
50 | bool unique() const { | ||||||||
51 | if (1 == fRefCnt.load(std::memory_order_acquire)) { | ||||||||
52 | // The acquire barrier is only really needed if we return true. It | ||||||||
53 | // prevents code conditioned on the result of unique() from running | ||||||||
54 | // until previous owners are all totally done calling unref(). | ||||||||
55 | return true; | ||||||||
56 | } | ||||||||
57 | return false; | ||||||||
58 | } | ||||||||
59 | |||||||||
60 | /** Increment the reference count. Must be balanced by a call to unref(). | ||||||||
61 | */ | ||||||||
62 | void ref() const { | ||||||||
63 | SkASSERT(this->getRefCnt() > 0)static_cast<void>( __builtin_expect(static_cast<bool >(this->getRefCnt() > 0), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 63, "this->getRefCnt() > 0"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
64 | // No barrier required. | ||||||||
65 | (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); | ||||||||
66 | } | ||||||||
67 | |||||||||
68 | /** Decrement the reference count. If the reference count is 1 before the | ||||||||
69 | decrement, then delete the object. Note that if this is the case, then | ||||||||
70 | the object needs to have been allocated via new, and not on the stack. | ||||||||
71 | */ | ||||||||
72 | void unref() const { | ||||||||
73 | SkASSERT(this->getRefCnt() > 0)static_cast<void>( __builtin_expect(static_cast<bool >(this->getRefCnt() > 0), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 73, "this->getRefCnt() > 0"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
74 | // A release here acts in place of all releases we "should" have been doing in ref(). | ||||||||
75 | if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { | ||||||||
76 | // Like unique(), the acquire is only needed on success, to make sure | ||||||||
77 | // code in internal_dispose() doesn't happen before the decrement. | ||||||||
78 | this->internal_dispose(); | ||||||||
79 | } | ||||||||
80 | } | ||||||||
81 | |||||||||
82 | private: | ||||||||
83 | |||||||||
84 | #ifdef SK_DEBUG | ||||||||
85 | /** Return the reference count. Use only for debugging. */ | ||||||||
86 | int32_t getRefCnt() const { | ||||||||
87 | return fRefCnt.load(std::memory_order_relaxed); | ||||||||
88 | } | ||||||||
89 | #endif | ||||||||
90 | |||||||||
91 | /** | ||||||||
92 | * Called when the ref count goes to 0. | ||||||||
93 | */ | ||||||||
94 | virtual void internal_dispose() const { | ||||||||
95 | #ifdef SK_DEBUG | ||||||||
96 | SkASSERT(0 == this->getRefCnt())static_cast<void>( __builtin_expect(static_cast<bool >(0 == this->getRefCnt()), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 96, "0 == this->getRefCnt()"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
97 | fRefCnt.store(1, std::memory_order_relaxed); | ||||||||
98 | #endif | ||||||||
99 | delete this; | ||||||||
100 | } | ||||||||
101 | |||||||||
102 | // The following friends are those which override internal_dispose() | ||||||||
103 | // and conditionally call SkRefCnt::internal_dispose(). | ||||||||
104 | friend class SkWeakRefCnt; | ||||||||
105 | |||||||||
106 | mutable std::atomic<int32_t> fRefCnt; | ||||||||
107 | |||||||||
108 | SkRefCntBase(SkRefCntBase&&) = delete; | ||||||||
109 | SkRefCntBase(const SkRefCntBase&) = delete; | ||||||||
110 | SkRefCntBase& operator=(SkRefCntBase&&) = delete; | ||||||||
111 | SkRefCntBase& operator=(const SkRefCntBase&) = delete; | ||||||||
112 | }; | ||||||||
113 | |||||||||
114 | #ifdef SK_REF_CNT_MIXIN_INCLUDE | ||||||||
115 | // It is the responsibility of the following include to define the type SkRefCnt. | ||||||||
116 | // This SkRefCnt should normally derive from SkRefCntBase. | ||||||||
117 | #include SK_REF_CNT_MIXIN_INCLUDE | ||||||||
118 | #else | ||||||||
119 | class SK_API SkRefCnt : public SkRefCntBase { | ||||||||
120 | // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system. | ||||||||
121 | #if defined(SK_BUILD_FOR_GOOGLE3) | ||||||||
122 | public: | ||||||||
123 | void deref() const { this->unref(); } | ||||||||
124 | #endif | ||||||||
125 | }; | ||||||||
126 | #endif | ||||||||
127 | |||||||||
128 | /////////////////////////////////////////////////////////////////////////////// | ||||||||
129 | |||||||||
130 | /** Call obj->ref() and return obj. The obj must not be nullptr. | ||||||||
131 | */ | ||||||||
132 | template <typename T> static inline T* SkRef(T* obj) { | ||||||||
133 | SkASSERT(obj)static_cast<void>( __builtin_expect(static_cast<bool >(obj), 1) ? static_cast<void>(0) : []{ do { if (sk_abort_is_enabled ()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n" , "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 133, "obj"); ; sk_abort_no_print(); } while (false); } } while (false); }() ); | ||||||||
134 | obj->ref(); | ||||||||
135 | return obj; | ||||||||
136 | } | ||||||||
137 | |||||||||
138 | /** Check if the argument is non-null, and if so, call obj->ref() and return obj. | ||||||||
139 | */ | ||||||||
140 | template <typename T> static inline T* SkSafeRef(T* obj) { | ||||||||
141 | if (obj) { | ||||||||
142 | obj->ref(); | ||||||||
143 | } | ||||||||
144 | return obj; | ||||||||
145 | } | ||||||||
146 | |||||||||
147 | /** Check if the argument is non-null, and if so, call obj->unref() | ||||||||
148 | */ | ||||||||
149 | template <typename T> static inline void SkSafeUnref(T* obj) { | ||||||||
150 | if (obj
| ||||||||
151 | obj->unref(); | ||||||||
152 | } | ||||||||
153 | } | ||||||||
154 | |||||||||
155 | /////////////////////////////////////////////////////////////////////////////// | ||||||||
156 | |||||||||
157 | // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16. | ||||||||
158 | // There's only benefit to using this if the deriving class does not otherwise need a vtable. | ||||||||
159 | template <typename Derived> | ||||||||
160 | class SkNVRefCnt { | ||||||||
161 | public: | ||||||||
162 | SkNVRefCnt() : fRefCnt(1) {} | ||||||||
163 | ~SkNVRefCnt() { | ||||||||
164 | #ifdef SK_DEBUG | ||||||||
165 | int rc = fRefCnt.load(std::memory_order_relaxed); | ||||||||
166 | SkASSERTF(rc == 1, "NVRefCnt was %d", rc)static_cast<void>( __builtin_expect(static_cast<bool >(rc == 1), 1) ? static_cast<void>(0) : [&]{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "assertf(%s): " "NVRefCnt was %d" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 166, "rc == 1", rc); ; sk_abort_no_print(); } while (false) ; } } while(false); }() ); | ||||||||
167 | #endif | ||||||||
168 | } | ||||||||
169 | |||||||||
170 | // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same: | ||||||||
171 | // - unique() needs acquire when it returns true, and no barrier if it returns false; | ||||||||
172 | // - ref() doesn't need any barrier; | ||||||||
173 | // - unref() needs a release barrier, and an acquire if it's going to call delete. | ||||||||
174 | |||||||||
175 | bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); } | ||||||||
176 | void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } | ||||||||
177 | void unref() const { | ||||||||
178 | if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { | ||||||||
179 | // restore the 1 for our destructor's assert | ||||||||
180 | SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed))fRefCnt.store(1, std::memory_order_relaxed); | ||||||||
181 | delete (const Derived*)this; | ||||||||
182 | } | ||||||||
183 | } | ||||||||
184 | void deref() const { this->unref(); } | ||||||||
185 | |||||||||
186 | // This must be used with caution. It is only valid to call this when 'threadIsolatedTestCnt' | ||||||||
187 | // refs are known to be isolated to the current thread. That is, it is known that there are at | ||||||||
188 | // least 'threadIsolatedTestCnt' refs for which no other thread may make a balancing unref() | ||||||||
189 | // call. Assuming the contract is followed, if this returns false then no other thread has | ||||||||
190 | // ownership of this. If it returns true then another thread *may* have ownership. | ||||||||
191 | bool refCntGreaterThan(int32_t threadIsolatedTestCnt) const { | ||||||||
192 | int cnt = fRefCnt.load(std::memory_order_acquire); | ||||||||
193 | // If this fails then the above contract has been violated. | ||||||||
194 | SkASSERT(cnt >= threadIsolatedTestCnt)static_cast<void>( __builtin_expect(static_cast<bool >(cnt >= threadIsolatedTestCnt), 1) ? static_cast<void >(0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf ("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 194, "cnt >= threadIsolatedTestCnt"); ; sk_abort_no_print (); } while (false); } } while(false); }() ); | ||||||||
195 | return cnt > threadIsolatedTestCnt; | ||||||||
196 | } | ||||||||
197 | |||||||||
198 | private: | ||||||||
199 | mutable std::atomic<int32_t> fRefCnt; | ||||||||
200 | |||||||||
201 | SkNVRefCnt(SkNVRefCnt&&) = delete; | ||||||||
202 | SkNVRefCnt(const SkNVRefCnt&) = delete; | ||||||||
203 | SkNVRefCnt& operator=(SkNVRefCnt&&) = delete; | ||||||||
204 | SkNVRefCnt& operator=(const SkNVRefCnt&) = delete; | ||||||||
205 | }; | ||||||||
206 | |||||||||
207 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||||
208 | |||||||||
209 | /** | ||||||||
210 | * Shared pointer class to wrap classes that support a ref()/unref() interface. | ||||||||
211 | * | ||||||||
212 | * This can be used for classes inheriting from SkRefCnt, but it also works for other | ||||||||
213 | * classes that match the interface, but have different internal choices: e.g. the hosted class | ||||||||
214 | * may have its ref/unref be thread-safe, but that is not assumed/imposed by sk_sp. | ||||||||
215 | * | ||||||||
216 | * Declared with the trivial_abi attribute where supported so that sk_sp and types containing it | ||||||||
217 | * may be considered as trivially relocatable by the compiler so that destroying-move operations | ||||||||
218 | * i.e. move constructor followed by destructor can be optimized to memcpy. | ||||||||
219 | */ | ||||||||
220 | template <typename T> class SK_TRIVIAL_ABI sk_sp { | ||||||||
221 | public: | ||||||||
222 | using element_type = T; | ||||||||
223 | |||||||||
224 | constexpr sk_sp() : fPtr(nullptr) {} | ||||||||
225 | constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {} | ||||||||
226 | |||||||||
227 | /** | ||||||||
228 | * Shares the underlying object by calling ref(), so that both the argument and the newly | ||||||||
229 | * created sk_sp both have a reference to it. | ||||||||
230 | */ | ||||||||
231 | sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {} | ||||||||
232 | template <typename U, | ||||||||
233 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | ||||||||
234 | sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {} | ||||||||
235 | |||||||||
236 | /** | ||||||||
237 | * Move the underlying object from the argument to the newly created sk_sp. Afterwards only | ||||||||
238 | * the new sk_sp will have a reference to the object, and the argument will point to null. | ||||||||
239 | * No call to ref() or unref() will be made. | ||||||||
240 | */ | ||||||||
241 | sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {} | ||||||||
242 | template <typename U, | ||||||||
243 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | ||||||||
244 | sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {} | ||||||||
245 | |||||||||
246 | /** | ||||||||
247 | * Adopt the bare pointer into the newly created sk_sp. | ||||||||
248 | * No call to ref() or unref() will be made. | ||||||||
249 | */ | ||||||||
250 | explicit sk_sp(T* obj) : fPtr(obj) {} | ||||||||
251 | |||||||||
252 | /** | ||||||||
253 | * Calls unref() on the underlying object pointer. | ||||||||
254 | */ | ||||||||
255 | ~sk_sp() { | ||||||||
256 | SkSafeUnref(fPtr); | ||||||||
257 | SkDEBUGCODE(fPtr = nullptr)fPtr = nullptr; | ||||||||
258 | } | ||||||||
259 | |||||||||
260 | sk_sp<T>& operator=(std::nullptr_t) { this->reset(); return *this; } | ||||||||
261 | |||||||||
262 | /** | ||||||||
263 | * Shares the underlying object referenced by the argument by calling ref() on it. If this | ||||||||
264 | * sk_sp previously had a reference to an object (i.e. not null) it will call unref() on that | ||||||||
265 | * object. | ||||||||
266 | */ | ||||||||
267 | sk_sp<T>& operator=(const sk_sp<T>& that) { | ||||||||
268 | if (this != &that) { | ||||||||
269 | this->reset(SkSafeRef(that.get())); | ||||||||
270 | } | ||||||||
271 | return *this; | ||||||||
272 | } | ||||||||
273 | template <typename U, | ||||||||
274 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | ||||||||
275 | sk_sp<T>& operator=(const sk_sp<U>& that) { | ||||||||
276 | this->reset(SkSafeRef(that.get())); | ||||||||
277 | return *this; | ||||||||
278 | } | ||||||||
279 | |||||||||
280 | /** | ||||||||
281 | * Move the underlying object from the argument to the sk_sp. If the sk_sp previously held | ||||||||
282 | * a reference to another object, unref() will be called on that object. No call to ref() | ||||||||
283 | * will be made. | ||||||||
284 | */ | ||||||||
285 | sk_sp<T>& operator=(sk_sp<T>&& that) { | ||||||||
286 | this->reset(that.release()); | ||||||||
287 | return *this; | ||||||||
288 | } | ||||||||
289 | template <typename U, | ||||||||
290 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | ||||||||
291 | sk_sp<T>& operator=(sk_sp<U>&& that) { | ||||||||
292 | this->reset(that.release()); | ||||||||
293 | return *this; | ||||||||
294 | } | ||||||||
295 | |||||||||
296 | T& operator*() const { | ||||||||
297 | SkASSERT(this->get() != nullptr)static_cast<void>( __builtin_expect(static_cast<bool >(this->get() != nullptr), 1) ? static_cast<void> (0) : []{ do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia/include/core/SkRefCnt.h" , 297, "this->get() != nullptr"); ; sk_abort_no_print(); } while (false); } } while(false); }() ); | ||||||||
298 | return *this->get(); | ||||||||
299 | } | ||||||||
300 | |||||||||
301 | explicit operator bool() const { return this->get() != nullptr; } | ||||||||
302 | |||||||||
303 | T* get() const { return fPtr; } | ||||||||
304 | T* operator->() const { return fPtr; } | ||||||||
305 | |||||||||
306 | /** | ||||||||
307 | * Adopt the new bare pointer, and call unref() on any previously held object (if not null). | ||||||||
308 | * No call to ref() will be made. | ||||||||
309 | */ | ||||||||
310 | void reset(T* ptr = nullptr) { | ||||||||
311 | // Calling fPtr->unref() may call this->~() or this->reset(T*). | ||||||||
312 | // http://wg21.cmeerw.net/lwg/issue998 | ||||||||
313 | // http://wg21.cmeerw.net/lwg/issue2262 | ||||||||
314 | T* oldPtr = fPtr; | ||||||||
315 | fPtr = ptr; | ||||||||
316 | SkSafeUnref(oldPtr); | ||||||||
317 | } | ||||||||
318 | |||||||||
319 | /** | ||||||||
320 | * Return the bare pointer, and set the internal object pointer to nullptr. | ||||||||
321 | * The caller must assume ownership of the object, and manage its reference count directly. | ||||||||
322 | * No call to unref() will be made. | ||||||||
323 | */ | ||||||||
324 | [[nodiscard]] T* release() { | ||||||||
325 | T* ptr = fPtr; | ||||||||
326 | fPtr = nullptr; | ||||||||
327 | return ptr; | ||||||||
328 | } | ||||||||
329 | |||||||||
330 | void swap(sk_sp<T>& that) /*noexcept*/ { | ||||||||
331 | using std::swap; | ||||||||
332 | swap(fPtr, that.fPtr); | ||||||||
333 | } | ||||||||
334 | |||||||||
335 | using sk_is_trivially_relocatable = std::true_type; | ||||||||
336 | |||||||||
337 | private: | ||||||||
338 | T* fPtr; | ||||||||
339 | }; | ||||||||
340 | |||||||||
341 | template <typename T> inline void swap(sk_sp<T>& a, sk_sp<T>& b) /*noexcept*/ { | ||||||||
342 | a.swap(b); | ||||||||
343 | } | ||||||||
344 | |||||||||
345 | template <typename T, typename U> inline bool operator==(const sk_sp<T>& a, const sk_sp<U>& b) { | ||||||||
346 | return a.get() == b.get(); | ||||||||
347 | } | ||||||||
348 | template <typename T> inline bool operator==(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ { | ||||||||
349 | return !a; | ||||||||
350 | } | ||||||||
351 | template <typename T> inline bool operator==(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ { | ||||||||
352 | return !b; | ||||||||
353 | } | ||||||||
354 | |||||||||
355 | template <typename T, typename U> inline bool operator!=(const sk_sp<T>& a, const sk_sp<U>& b) { | ||||||||
356 | return a.get() != b.get(); | ||||||||
357 | } | ||||||||
358 | template <typename T> inline bool operator!=(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ { | ||||||||
359 | return static_cast<bool>(a); | ||||||||
360 | } | ||||||||
361 | template <typename T> inline bool operator!=(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ { | ||||||||
362 | return static_cast<bool>(b); | ||||||||
363 | } | ||||||||
364 | |||||||||
365 | template <typename C, typename CT, typename T> | ||||||||
366 | auto operator<<(std::basic_ostream<C, CT>& os, const sk_sp<T>& sp) -> decltype(os << sp.get()) { | ||||||||
367 | return os << sp.get(); | ||||||||
368 | } | ||||||||
369 | |||||||||
370 | template <typename T> sk_sp(T*) -> sk_sp<T>; | ||||||||
371 | |||||||||
372 | template <typename T, typename... Args> | ||||||||
373 | sk_sp<T> sk_make_sp(Args&&... args) { | ||||||||
374 | return sk_sp<T>(new T(std::forward<Args>(args)...)); | ||||||||
375 | } | ||||||||
376 | |||||||||
377 | /* | ||||||||
378 | * Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null). | ||||||||
379 | * | ||||||||
380 | * This is different than the semantics of the constructor for sk_sp, which just wraps the ptr, | ||||||||
381 | * effectively "adopting" it. | ||||||||
382 | */ | ||||||||
383 | template <typename T> sk_sp<T> sk_ref_sp(T* obj) { | ||||||||
384 | return sk_sp<T>(SkSafeRef(obj)); | ||||||||
385 | } | ||||||||
386 | |||||||||
387 | template <typename T> sk_sp<T> sk_ref_sp(const T* obj) { | ||||||||
388 | return sk_sp<T>(const_cast<T*>(SkSafeRef(obj))); | ||||||||
389 | } | ||||||||
390 | |||||||||
391 | #endif |
1 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
4 | ||||
5 | #ifndef mozilla_cxxalloc_h | |||
6 | #define mozilla_cxxalloc_h | |||
7 | ||||
8 | /* | |||
9 | * We implement the default operators new/delete as part of | |||
10 | * libmozalloc, replacing their definitions in libstdc++. The | |||
11 | * operator new* definitions in libmozalloc will never return a NULL | |||
12 | * pointer. | |||
13 | * | |||
14 | * Each operator new immediately below returns a pointer to memory | |||
15 | * that can be delete'd by any of | |||
16 | * | |||
17 | * (1) the matching infallible operator delete immediately below | |||
18 | * (2) the matching system |operator delete(void*, std::nothrow)| | |||
19 | * (3) the matching system |operator delete(void*) noexcept(false)| | |||
20 | * | |||
21 | * NB: these are declared |noexcept(false)|, though they will never | |||
22 | * throw that exception. This declaration is consistent with the rule | |||
23 | * that |::operator new() noexcept(false)| will never return NULL. | |||
24 | * | |||
25 | * NB: mozilla::fallible can be used instead of std::nothrow. | |||
26 | */ | |||
27 | ||||
28 | #ifndef MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline | |||
29 | # define MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) | |||
30 | #endif | |||
31 | ||||
32 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size) noexcept(false) { | |||
33 | return moz_xmalloc(size); | |||
34 | } | |||
35 | ||||
36 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size, | |||
37 | const std::nothrow_t&) noexcept(true) { | |||
38 | return malloc_impl(size); | |||
39 | } | |||
40 | ||||
41 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size) noexcept(false) { | |||
42 | return moz_xmalloc(size); | |||
43 | } | |||
44 | ||||
45 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size, | |||
46 | const std::nothrow_t&) noexcept(true) { | |||
47 | return malloc_impl(size); | |||
48 | } | |||
49 | ||||
50 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr) noexcept(true) { | |||
51 | return free_impl(ptr); | |||
| ||||
52 | } | |||
53 | ||||
54 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
55 | const std::nothrow_t&) noexcept(true) { | |||
56 | return free_impl(ptr); | |||
57 | } | |||
58 | ||||
59 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr) noexcept(true) { | |||
60 | return free_impl(ptr); | |||
61 | } | |||
62 | ||||
63 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[]( | |||
64 | void* ptr, const std::nothrow_t&) noexcept(true) { | |||
65 | return free_impl(ptr); | |||
66 | } | |||
67 | ||||
68 | #if defined(XP_WIN) | |||
69 | // We provide the global sized delete overloads unconditionally because the | |||
70 | // MSVC runtime headers do, despite compiling with /Zc:sizedDealloc- | |||
71 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
72 | size_t /*size*/) noexcept(true) { | |||
73 | return free_impl(ptr); | |||
74 | } | |||
75 | ||||
76 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr, | |||
77 | size_t /*size*/) noexcept(true) { | |||
78 | return free_impl(ptr); | |||
79 | } | |||
80 | #endif | |||
81 | ||||
82 | #endif /* mozilla_cxxalloc_h */ |